﻿/**
<code>
  <author name="Zealic" email="zealic(at)gmail.com" type="Creator"/>
</code>
**/
using System;
using System.Collections.Generic;
using System.Reflection.Emit;
using System.Linq.Expressions;
using System.Xml;
using System.IO;


namespace Zealib.Mapper
{
    /// <summary>
    /// Poco mapper.
    /// </summary>
    /// <typeparam name="TSource">Source type.</typeparam>
    /// <typeparam name="TDestination">Right type.</typeparam>
    public class PocoMapper<TSource, TDestination> : IMapper<TSource, TDestination>
    {
        private bool m_Compiled = false;
        private Action<TSource, TDestination> m_MapHandler;
        
        /// <summary>
        /// Create a mapper.
        /// </summary>
        public PocoMapper()
            : this(AutoGenerateMapping())
        {
        }

        public PocoMapper(
            IDictionary<
                Expression<Func<TSource, object>>,
                Expression<Func<TDestination, object>>
            > mappings)
        {
        }

        public PocoMapper(Action<TSource, TDestination> mapHandler)
        {
            m_MapHandler = mapHandler;
        }

        public static PocoMapper<TSource, TDestination> FromXml(XmlReader xmlReader)
        {
            if (xmlReader == null) throw new ArgumentNullException("xmlReader");
            throw new NotImplementedException();
        }

        public static PocoMapper<TSource, TDestination> FromXml(string xml)
        {
            if(xml == null) throw new ArgumentNullException("xml");
            StringReader reader = new StringReader(xml);
            return FromXml(XmlReader.Create(reader));
        }

        /// <summary>
        /// Create DynamicMethod.
        /// </summary>
        protected DynamicMethod CreateDynamicMethod()
        {
            string name = string.Format(
                "Mapper<{0}, {1}>",
                typeof(TSource).FullName,
                typeof(TDestination).FullName);
            Type[] parameterTypes = new[] { typeof(TSource), typeof(TDestination) };
            return new DynamicMethod(
                name, null,
                parameterTypes,
                typeof(TSource));
        }

        private static IDictionary<
                Expression<Func<TSource, object>>,
                Expression<Func<TDestination, object>>
            > AutoGenerateMapping()
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// Compile map to delegate.
        /// </summary>
        /// <returns>Compiled map handler.</returns>
        protected Action<TSource, TDestination> CreateHandler()
        {
            DynamicMethod method = CreateDynamicMethod();
            //TODO:Emit all mapped member assignment
            method.GetILGenerator().Emit(OpCodes.Ret);
            var handler = (Action<TSource, TDestination>)method
                .CreateDelegate(typeof(Action<TSource, TDestination>));
            m_Compiled = true;
            return handler;
        }

        /// <summary>
        /// Map object.
        /// </summary>
        /// <param name="source">Source object.</param>
        /// <param name="destination">Destination object.</param>
        public void Map(TSource source, TDestination destination)
        {
            if(!m_Compiled)
                m_MapHandler = CreateHandler();
            m_MapHandler(source, destination);
        }

    }
}
